#include "antianaphylaxis_queue.h"

#include <vector>
#include <string>
#include "public_define.h"
#include "dat_parser.h"
#include "eventloop.h"
#include "adr_component.h"
#include "encode_srv.pb.h"
#include "adr_uploadstatus.pb.h"
#include "tool.h"
#include <set>

#include "common_opr_system.h"
#include "file_task.h"
#include "filemanagercommand.h"
#include "fileReupload.h"

using namespace DcAdr;
#define CODEC_PROBE_H265_I_FRAME(data) (0x0 == ((char *)data)[0] && 0x0 == ((char *)data)[1] && 0x0 == ((char *)data)[2] && 0x1 == ((char *)data)[3] && 0x40 == ((char *)data)[4])
set<string> DesensCamSet = {
    ENCODE_SRV_DESENS_H265_CAM0,
    ENCODE_SRV_DESENS_H265_CAM1,
    ENCODE_SRV_DESENS_H265_CAM2,
    ENCODE_SRV_DESENS_H265_CAM3,
    ENCODE_SRV_DESENS_H265_CAM4,
    ENCODE_SRV_DESENS_H265_CAM5,
    ENCODE_SRV_DESENS_H265_CAM6,
    ENCODE_SRV_DESENS_H265_CAM7,
    ENCODE_SRV_DESENS_H265_CAM8,
    ENCODE_SRV_DESENS_H265_CAM9,
    ENCODE_SRV_DESENS_H265_CAM10};

AntianaphylaxisQueue::AntianaphylaxisQueue(/* args */)
{
}

AntianaphylaxisQueue::~AntianaphylaxisQueue()
{
}

AntianaphylaxisQueue &AntianaphylaxisQueue::getInstance()
{
    static AntianaphylaxisQueue queue;
    return queue;
}

void AntianaphylaxisQueue::setPublishHandle(adr_component *component)
{
    m_component = component;
}

void AntianaphylaxisQueue::addQueue()
{
}

// 定义AntianaphylaxisQueue类的sendUploadStatus2Sts方法，用于向STS发送上传状态
// 参数flag表示上传状态（true/false）
void AntianaphylaxisQueue::sendUploadStatus2Sts(bool flag)
{
    // 创建AdrTrigger::UploadStatus类型的临时对象tmp，用于存储上传状态信息
    AdrTrigger::UploadStatus tmp;
    
    // 设置上传状态（flag值）到protobuf对象中
    tmp.set_status(flag);
    
    // 设置时间戳（当前时间秒级，通过getTime()获取毫秒时间后除以1000转换）
    tmp.set_time_stamp(getTime() / 1000);
    
    // 定义字符串adrStatus，用于存储序列化后的protobuf数据
    string adrStatus;
    
    // 将protobuf对象tmp序列化到adrStatus字符串中（Partial表示允许部分字段序列化）
    tmp.SerializePartialToString(&adrStatus);
    
    // 检查m_component是否有效（不为空）
    if (m_component != nullptr)
    {
        // 通过m_component的publish方法发送消息，主题为"adr-AdrTrigger.UploadStatus"
        m_component->publish(adrStatus, "adr-AdrTrigger.UploadStatus");
        
        // 打印日志，记录成功发送状态，包含flag值
        Log_Info("[DataCollect] send uploadstatus to sts; flage:{}", flag);
    }
    else
    {
        // 若m_component为空，打印日志记录发送失败
        Log_Info("[DataCollect] send uploadstatus to sts faild;m_component is null");
    }
}

void AntianaphylaxisQueue::dealQueue()
{
    if (global_data::g_adc_status != 0x06)
    {
        return;
    }
    m_get6 = true;
    if((m_get6==true)&&(m_get6_before==false))
    {
        Log_Info("sleep 3s for encode_srv init");
        sleep(3);//如果m_get6从false变为true，说明开启了新的脱敏任务，为了让编解码有时间进行初始化，在此进行3秒延时
    }
    m_get6_before=m_get6;
    if (m_component == nullptr)
    {
        Log_ERROR("[DataCollect] component empty... ");
        return;
    }

    // 工作状态 进来5次认为脱敏处理完成上传文件，置为none下次再读文件加入任务队列。否则工作状态<5次直接退出
    if (ANTPL_WORKING_STATUS::NONE != m_antplStats)
    {
        m_times++;
        if (m_times > 5)
        {
            m_antplStats = ANTPL_WORKING_STATUS::NONE;
            delete m_record;
            m_record = nullptr;
            m_times = 0;
            // m_hasDealed = true;
            Log_Info("[xiangrui debug] MoveAfterFile:{}", m_curretDealFile.afterFile);
            std::string fileName = Util::getFileBaseName(m_curretDealFile.afterFile);
            std::string orgAfterFilePath = global_data::g_file_path + fileName;
            std::string newAfterFilePath = FileManagerCommand::getInstance()->saveFile(m_curretDealFile.level, orgAfterFilePath); // 脱敏完成后的文件放到对应的level下面，做文件管理
            // 脱敏后文件存在并且有之前云端下发的taskid 上传刚读取的第一个文件
            if ((0 == access(m_curretDealFile.afterFile.c_str(), F_OK)) && (!(m_curretDealFile.taskid.empty())))
            {
                std::string filePath = m_curretDealFile.afterFile;
                std::string taskid = m_curretDealFile.taskid;
                //int level = m_curretDealFile.level;
                auto fun = [=]()
                {
                    
                    //FileReupload::getInstance().writeFileInfo(filePath, taskid, level, "NO"); // 写入reupload.json做文件上传
                };
                appendEvent(ThreadType::E_InVideoAntianaphylaxis, fun);
                //appendEvent(ThreadType::E_InFileUploadThread, fun);
            }
            else
            {
                Log_Info("tuomin after upload file faild; file: {}  taskid: {}", m_curretDealFile.afterFile, m_curretDealFile.taskid);
            }
        }
        return;
    }

    // 加入线程队列
    auto func = [=]()
    {
        std::string fileStr, afterFilePath;
        if (!getOneFile(fileStr, afterFilePath)) // 没有读到脱敏任务
        {
            if (m_get6)
            {
                m_get6 = false;
                m_get6_before=m_get6;
                sendUploadStatus2Sts(true);
            }

            return;
        }
        Log_Info("[DataCollect] befFile: {}  afterFilePath: {}", fileStr, afterFilePath);

        m_antplStats = ANTPL_WORKING_STATUS::WORKING;
        std::string fileName = Util::getFileBaseName(m_curretDealFile.afterFile); // 脱敏后的文件先罗盘在/ds/datacollect下面，脱敏完成后移动到level下面做文件管理
        std::string orgAfterFilePath = global_data::g_file_path + fileName;
        m_record = new DataRecord();
        // m_record->initializeRecord(afterFilePath); // zjs_todo;如果这个文件存在，会覆盖写
        m_record->initializeRecord(orgAfterFilePath); // 写到/ds/datacollect目录
        // 读取文件
        vector<DatParser::ReplayData> repVec;
        DatParser parse;
        parse.parse(fileStr, repVec);
        Log_Info("[DataCollect] DatParser count: {}", repVec.size());

        std::map<std::string, bool> isIframeMap = {
            {"adr-EncodeSrv.EncodeH265-CAM0", false},
            {"adr-EncodeSrv.EncodeH265-CAM1", false},
            {"adr-EncodeSrv.EncodeH265-CAM2", false},
            {"adr-EncodeSrv.EncodeH265-CAM3", false},
            {"adr-EncodeSrv.EncodeH265-CAM4", false},
            {"adr-EncodeSrv.EncodeH265-CAM5", false},
            {"adr-EncodeSrv.EncodeH265-CAM6", false},
            {"adr-EncodeSrv.EncodeH265-CAM7", false},
            {"adr-EncodeSrv.EncodeH265-CAM8", false},
            {"adr-EncodeSrv.EncodeH265-CAM9", false},
            {"adr-EncodeSrv.EncodeH265-CAM10", false},
        };
        // 发送数据给编码模块
        for (DatParser::ReplayData &data : repVec)
        {
            std::string topic(data.head.name);
            topic = Util::stringReplace(topic, "encode_srv", "adr");

            EncodeSrv::EncodeH265 enc;
            if (!enc.ParsePartialFromString(data.data))
            {
                Log_Topic("publish Parse EncodeSrv::EncodeH265 failed");
                continue;
            }
            // 给编解码第一帧是I帧 begin，在dat罗盘的时候已经过滤了一次，此处给编解码发送再过滤一次
            if (JudgeIsIFrame(topic, enc, isIframeMap) == false)
            {
                continue;
            }
            // 给编解码第一帧是I帧 end
            Log_Topic("publish topic: {},frame id:{},cam id:", topic,enc.frame_id(),enc.camid());
            try
            {
                m_component->publish(data.data, topic);
                std::this_thread::sleep_for(std::chrono::milliseconds(10)); // 发送帧率100FPS
            }
            catch (const std::exception &e)
            {
                Log_ERROR(e.what());
            }
        }
        m_antplStats = ANTPL_WORKING_STATUS::RECEIVING;
    };
    appendEvent(ThreadType::E_InVideoAntianaphylaxis, func);
}
bool AntianaphylaxisQueue::JudgeIsIFrame(std::string &topic, EncodeSrv::EncodeH265 &enc, std::map<std::string, bool> &isIframeMap)
{
    // Log_Info("[xiangrui debug] [JudgeIsIFrame] topic:{}", topic);

    if (Contain_Map(isIframeMap, topic))
    {
        if (isIframeMap[topic] == false)
        {
            if (enc.frame_data().size() <5)
            {
                Log_ERROR("h265Data size <5");
                return false;
            }
            if (CODEC_PROBE_H265_I_FRAME(enc.frame_data().c_str()))
            {
                Log_Info("is I frame,topic:{}", topic);
                isIframeMap[topic] = true;
                return true;
            }
            else
            {
                Log_Info("is not I frame,topic:{}", topic);
                return false;
            }
            // const char *frameData = enc.frame_data().c_str();
            // if (frameData != nullptr)
            // {
            //     if (enc.frame_data().size() >= 5)
            //     {
            //         if (frameData[0] == 0x0 && frameData[1] == 0x0 && frameData[2] == 0x0 && frameData[3] == 0x1 && frameData[4] == 0x40)
            //         {
            //             Log_Info("is I frame,topic:{}",topic);
            //             isIframeMap[topic] = true;
            //             return true;
            //         }
            //         else
            //         {
            //             Log_Info("is not I frame,topic:{}",topic);
            //             return false;
            //         }
            //     }
            //     else
            //     {
            //         Log_Info("enc.frame_data().size()<5");
            //         return false;
            //     }
            // }
            // else
            // {
            //     Log_Info("frameData is nullptr");
            //     return false;
            // }
        }
        else
        {
            return true;
        }
    }
    else
    {
        Log_Info("Contain_Map(isIframeMap, topic) is false,topic:{}", topic);
        return false;
    }
}
bool AntianaphylaxisQueue::receiveDesensData(const ProtoData &data)
{
    if (DesensCamSet.find(*data.topic) == DesensCamSet.end())
    {
        return false;
    }
    if (m_record != nullptr)
    {
        string topic = *data.topic;
        topic = Util::stringReplace(topic, "DesensCAM", "CAM"); // cavision不支持脱敏后的topic，先转出脱敏前topic记录。用文件名中的类型区别
        m_record->record(topic, data.timestamp, *data.data);
    }
    m_antplStats = ANTPL_WORKING_STATUS::RECEIVING;
    m_times = 0;
    return true;
}

bool AntianaphylaxisQueue::getOneFile(std::string &filePath, std::string &afterFilePath)
{
    std::fstream i(global_data::g_local_conf_path);
    if (!i)
    {
        Log_ERROR("get local file error!");
        return false;
    }
    std::stringstream ss;
    ss << i.rdbuf();
    std::string desenListStr = ss.str();
    i.close();

    Log_Info("Queue before: {}", desenListStr);

    if (desenListStr.empty())
    {
        Log_Info("Queue empty: {}", desenListStr);
        return false;
    }

    CommonOprJson::jsonstrformat(desenListStr);
    // 读json
    Json::Reader reader;
    Json::Value root;
    if ((!reader.parse(desenListStr, root)) || (!root.isArray())) // 解析不成功或者根节点不是数组就 有问题
    {
        Log_Info("json parse error! {}", desenListStr);
        return false;
    }

    Json::Value rootNew;
    for (int i = 0; i < root.size(); ++i)
    {
        if (0 == i) // 取第一个
        {
            m_curretDealFile.befFile = JsonToValue<std::string>(root[i]["fileNameBef"]);
            m_curretDealFile.afterFile = JsonToValue<std::string>(root[i]["fileNameAfter"]);
            m_curretDealFile.level = JsonToValue<int>(root[i]["level"]);
            m_curretDealFile.taskid = JsonToValue<std::string>(root[i]["taskId"]);

            Log_Info("getfile; befFile: {}  afterFile: {}  taskid: {}", m_curretDealFile.befFile, m_curretDealFile.afterFile, m_curretDealFile.taskid);

            filePath = m_curretDealFile.befFile;
            afterFilePath = m_curretDealFile.afterFile;
        }
        else ////删掉第一个，后面再写文件
        {
            rootNew.append(root[i]);
        }
    }

    std::string newDesen;
    if (rootNew.empty())
    {
    }
    else
    {
        newDesen = rootNew.toStyledString();
    }

    // Log_Info("Queue after: {}", newDesen);

    std::fstream out(global_data::g_local_conf_path, std::fstream::trunc | std::fstream::in | std::fstream::out);
    if (!out)
    {
        Log_ERROR("get local file error!");
        return false;
    }
    out.write(newDesen.c_str(), newDesen.size());
    out.close();
    return true;
}

void AntianaphylaxisQueue::findAndWriteTaskidInFile(const std::string &filePath, const std::string &taskId)
{
    fstream in(global_data::g_local_conf_path);
    string jsonString;
    if (in)
    {
        stringstream buffer;
        buffer << in.rdbuf();
        jsonString = buffer.str();
        in.close();
    }
    CommonOprJson::jsonstrformat(jsonString);

    // 读json
    Json::Reader reader;
    Json::Value root;
    if ((!reader.parse(jsonString, root)) || (!root.isArray())) // 解析不成功或者根节点不是数组就 有问题
    {
        Log_Info("json parse error! {}", jsonString);
        return;
    }

    // taskid附上，等脱敏完成上传。
    for (int i = 0; i < root.size(); ++i)
    {
        Json::Value &fileInfo = root[i];
        if (fileInfo["fileNameAfter"] == filePath)
        {
            fileInfo["taskId"] = taskId;
            break;
        }
    }
    std::string writeStr = root.toStyledString();
    Log_Info("after wirte 22: {}", writeStr);

    // 写json文件       //std::fstream::trunc 截断模式，打开文件时，如果文件已存在，清空文件的所有内容；如果文件不存在，创建新文件。
    std::fstream i(global_data::g_local_conf_path, std::fstream::trunc | std::fstream::in | std::fstream::out);
    if (!i)
    {
        Log_ERROR("get local file error!");
        return;
    }
    i.write(writeStr.c_str(), writeStr.size());
    i.close();
    return;
}

void AntianaphylaxisQueue::writeFileName(std::string befor, std::string after, int level)
{
    fstream in(global_data::g_local_conf_path);
    string jsonString;
    if (in)
    {
        stringstream buffer;
        buffer << in.rdbuf();
        jsonString = buffer.str();
        in.close();
    }
    CommonOprJson::jsonstrformat(jsonString);

    // 读json
    Json::Reader reader;
    Json::Value root;

    if (jsonString.empty())
    {
    }
    else
    {
        if ((!reader.parse(jsonString, root)) || (!root.isArray())) // 解析不成功或者根节点不是数组就 有问题
        {
            Log_Info("json parse error! {}", jsonString);
            return;
        }
    }

    Json::Value oneFile;
    oneFile["fileNameBef"] = befor;
    oneFile["fileNameAfter"] = after;
    oneFile["level"] = level;
    root.append(oneFile);

    std::string writeStr = root.toStyledString();
    Log_Info("after wirte: {}", writeStr);

    // 写json文件
    std::fstream i(global_data::g_local_conf_path, std::fstream::trunc | std::fstream::in | std::fstream::out);
    if (!i)
    {
        Log_ERROR("get local file error!");
        return;
    }
    i.write(writeStr.c_str(), writeStr.size());
    i.close();
    return;
}
